Computer languages that support independent constructed program units must resolve symbolic references from one program unit to an “external” object in another program unit. For example, most C and C++ programming language environments support separate compilation of source code files into object code files. When a first source code file references an object defined in a second source code file, the compiler typically creates an “external reference” to that object in the object code that it generates when it compiles the first source code file. The external reference within the object code is eventually resolved into an actual address.
A number of approaches have been developed for resolving external references. For example, with a “static linking” approach, external references are resolved at link time, i.e. when the separately compiled object code files are combined together to form a complete, executable program. Another approach is “dynamic linking,” in which some object code files are grouped into modules typically called “dynamic link libraries” or “DLLs.” When a program linked with DLLs is executed, the DLLs are not combined with the program until the program is loaded into memory for execution. In the dynamic linking approach, external references are resolved at load time.
One popular programming language that supports separate compilation is JAVA, a platform-independent, object-oriented language developed by Sun Microsystems. In JAVA, the attributes and methods for a class of objects are typically defined in its own source file, which is separately compiled into an architecture-neutral object file containing bytecodes that are interpreted by the target platform. Since it is common for one class to reference objects that belong to another class, JAVA source files will commonly require external references to other objects and their classes.
Lately, there has been much interest in using JAVA as a development language for applications that interact with a relational database system. A relational database system stores information in tables organized into rows and columns. To retrieve the information, a database application submits queries and other “calls” to a database server process, which determines which information in the tables satisfies the request.
A multi-user database allows multiple users to connect to the database concurrently in many separate sessions, and typically only a few of the sessions are actively using the database at any particular time by making calls. When designing a run-time environment for database applications, scalability in terms of the number of simultaneous users who can establish separate sessions is very important. A significant constraint for user scalability is the size of the memory “footprint” that each session consumes, and it is desirable to reduce the session memory footprint to improve scalability.
JAVA defines the lifetime of many objects, especially system objects, to extend throughout the duration of a session. Some of these objects, however, are infrequently used. Resolving external references to such objects at link time or load time according to conventional approaches entails loading these objects when the run-time environment is executed, either because they are statically part of the executable image or are dynamically loaded from a DLL. These objects consume session memory and reduce the user scalability of the database system.
Since session memory is allocated for each active client session, user scalability is improved by reducing the memory requirements of session memory. Memory requirements for session memory may be reduced by deferring the allocation of external objects in session memory until those external objects are actually accessed. This is referred to as lazy evaluation for resolving external objects. In particular, these external objects (whose allocation in session memory is designated to be deferred until they are accessed) are so designated by creating external references to them, for example by implementers of the run-time environment. In addition, if the external objects are easily “recreatable,” the objects can be deallocated and later allocated (or found in a shared memory) through the lazy evaluation process.
One example of an external object whose allocation would be desirable to defer is a class definition for a required, but rarely used system class, such as a system error class. This class typically requires much memory to be allocated for static member variables, for example, for error messages that are output as well as for the byte codes of the error handling instructions. Therefore, allocating a system error class in session memory increases the session memory footprint and thereby reduces the number of users who can establish a session at one time, even though that allocated session memory is rarely used. Accordingly, the allocation of the class definition for such a class is deferred until the class is actually used. Furthermore, even when the class definition is allocated upon access, the class definition can be allocated in non-session memory.
Objects stored in longer-duration memory may themselves include numerous recreatable external references. For example, the code for a particular class may use recreatable external references to identify other classes, such as the superclass of the particular class. In addition, objects in longer-duration memory may use recreatable external references to refer to objects that reside in a constant pool.
A constant pool is an area of memory that holds the data for all of the literal values used in a program's code. Such data may include, for example, text strings and numeric constants. Typically, literals are handled by creating a table of pointers, where each of the pointers points to a literal value. When code that references a literal value is compiled, the literal value is assigned to a global variable, and the code that accesses the literal value does so through a reference to the global variable. To avoid loading a potentially large amount of data associated with such global variables, they may be accessed using recreatable external references. This is also used to maintain semantics if objects from different class files might be equivalent.
In addition to recreatable external references associated with global variable that correspond to literals in a constant pool, longer-duration memory may also contain recreatable external references to other types of objects. For example, longer-duration memory may contain recreatable external references to methods identified in a method table within longer-duration memory. The method table may be accessed, for example, when a method in a particular class makes a call to another method in the same class.
When recreatable external references to objects in shorter-duration memory are used in longer-duration memory, it results in a significant performance penalty because the objects in the longer-duration memory do not contain information specific to any particular call. However, because the recreated objects are realized on a per-call basis, the cached values array resides in the call memory, which is private. Consequently, recreatable external references in longer-duration memory do not contain pointers to the corresponding cached values arrays. However, the cached values array that corresponds to an recreatable external reference must be inspected every time the recreatable external reference is dereferenced in order to determine whether the referenced object has already been realized, and if so, where the realized instance of the object is located. Thus, every time a recreatable external reference in longer-duration memory is dereferenced, relatively expensive measures must be taken to locate the appropriate private cached values array to determine whether the referenced object has already been realized.
Unfortunately, in systems that use lazy evaluation for resolving recreatable external references, the runtime performance penalty for dereferencing such external references may be significant. Based on the foregoing, it is desirable to provide a system that allows lazy evaluation of external references, but reduces the runtime performance penalty.